﻿using System;

namespace Kooboo.CMS.FolderSyncWrapper
{
    using Kooboo.CMS.Content.Models;
    using Kooboo.CMS.Content.Services;
    using Kooboo.CMS.Sites.Models;
    using Kooboo.CMS.Sites.Persistence;
    using System.Collections.Generic;
    using System.Linq;

    public class TextFolderManagerWrapper : TextFolderManager
    {
        public TextFolderManagerWrapper()
        {
            this.SiteProvider = Kooboo.CMS.Sites.Persistence.Providers.SiteProvider;
        }

        ISiteProvider SiteProvider
        {
            get;
            set;
        }

        #region Base functions facade

        private void BaseAdd(Repository repository, TextFolder item)
        {
            base.Add(repository, item);
        }

        private void BaseUpdate(Repository repository, TextFolder @new, TextFolder old)
        {
            base.Update(repository, @new, old);
        }

        private void BaseRemove(Repository repository, TextFolder item)
        {
            base.Remove(repository, item);
        }

        #endregion

        public override void Add(Repository repository, TextFolder item)
        {
            base.Add(repository, item);

            var operatedRepositories = new List<Repository>();
            operatedRepositories.Add(repository);

            this.SyncToSubSites(
                Site.Current,
                item,
                operatedRepositories,
                (Repository, CurrentFolder) =>
                {
                    this.BaseAdd(Repository, CurrentFolder);
                }
            );
        }

        public override void Update(Repository repository, TextFolder @new, TextFolder old)
        {
            base.Update(repository, @new, old);

            var operatedRepositories = new List<Repository>();
            operatedRepositories.Add(repository);

            this.SyncToSubSites(
                Site.Current,
                @new,
                old,
                operatedRepositories,
                (Repository, NewFolder, OldFolder) =>
                {
                    this.BaseUpdate(Repository, NewFolder, OldFolder);
                }
            );
        }

        public override void Remove(Repository repository, TextFolder item)
        {
            base.Remove(repository, item);

            var operatedRepositories = new List<Repository>();
            operatedRepositories.Add(repository);

            this.SyncToSubSites(
                Site.Current,
                item,
                operatedRepositories,
                (Repository, CurrentFolder) =>
                {
                    this.BaseRemove(Repository, CurrentFolder);
                }
            );
        }

        private void SyncToSubSites(Site site, TextFolder folder, List<Repository> operatedRepositories, Action<Repository, TextFolder> syncAction)
        {
            foreach (var subSite in this.SiteProvider.ChildSites(site))
            {
                if (syncAction != null)
                {
                    var repository = subSite.GetRepository();

                    if (operatedRepositories.Any(item => item.Name == repository.Name))
                    {
                        continue;
                    }

                    syncAction(repository, folder);

                    operatedRepositories.Add(repository);
                }

                this.SyncToSubSites(subSite, folder, operatedRepositories, syncAction);
            }
        }

        private void SyncToSubSites(Site site, TextFolder @new, TextFolder old, List<Repository> operatedRepositories, Action<Repository, TextFolder, TextFolder> syncAction)
        {
            foreach (var subSite in this.SiteProvider.ChildSites(site))
            {
                if (syncAction != null)
                {
                    var repository = subSite.GetRepository();

                    if (operatedRepositories.Any(item => item.Name == repository.Name))
                    {
                        continue;
                    }

                    syncAction(repository, @new, old);

                    operatedRepositories.Add(repository);
                }

                this.SyncToSubSites(subSite, @new, old, operatedRepositories, syncAction);
            }
        }
    }
}
